package com.automapper.interceptor;

import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.automapper.utils.MappedStatementBuilder;
import com.automapper.utils.ParameterUtils;

/**
 * 采用拦截器执行动态sql时，重新创建MappedStatement, 防止并发查询时返回映射结果类型出现错误，创建了本拦截器，
 * 本拦截器会拦截Executor的query方法，在创建cacheKey时将分页参数包含其中。 
 * 签名里要拦截的类型只能是接口。
 * @author K
 *
 */
@Intercepts({
    @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class }) 
})
public class AutoMapperCacheInterceptor implements Interceptor {
	
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		Object parameter = invocation.getArgs()[1];
				
		// parameter不是通过AutoMapperRepository方法传入参数，不做任何处理，传递给下一个拦截器处理
		if (!ParameterUtils.isAutoMapperParameter(parameter)) {
			return invocation.proceed();
		}
		        
		Object[] args = invocation.getArgs();
		MappedStatement ms = (MappedStatement) args[0];
        // 重新创建MappedStatement，替换原来MappedStatement对象，防止并发查询时返回映射结果类型出现错误
        args[0] = MappedStatementBuilder.build(ms);
		
        return invocation.proceed();
	}

	@Override
	public Object plugin(Object target) {
		if (target == null) {
			return target;
        } 
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {}

}
